package au.com.langdale.gwt.client.ui;

import java.util.ArrayList;

import au.com.langdale.gwt.client.binding.CheckBoxBinding;
import au.com.langdale.gwt.client.binding.LabelBinding;
import au.com.langdale.gwt.client.binding.TextBoxBinding;
import au.com.langdale.gwt.client.model.ModelListener;
import au.com.langdale.gwt.client.model.Property;
import au.com.langdale.gwt.client.remote.EditManager;

import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBoxBase;

/**
 * A base class for data bound forms.<p>  
 * 
 * A Form is a Composite whose widgets can be 
 * conveniently bound to a model object.<p>
 * 
 * A concrete form instantiates widgets and implements
 * the bindAll() method.<p>
 * 
 * The bindAll() method should establish bindings
 * by calling bind() for each widget.<p>
 * 
 * Binding is actually performed when a model is provided
 * by setModel().<p>
 * 
 *  TODO: Form is a naive design that works for one model object.
 *  TODO: Form assumes it 'owns' all the bindings in the EditManager.<p>
 *  
 * @author adv
 *
 */
public abstract class Form extends Composite implements ModelListener {

	private EditManager editManager = new EditManager() {
		protected void push(ArrayList updates, ArrayList deleted) {
			// just a placeholder
		}
	};

	private Object model;
	
	public Form() {
		editManager.addModelListener(this);
	}

	public Object getModel() {
		return model;
	}

	public void setModel(Object model) {
		editManager.removeBindings();
		this.model = model;
		bindAll();
	}

	public EditManager getEditManager() {
		return editManager;
	}

	public void setEditManager(EditManager manager) {
		editManager.removeModelListener(this);
		editManager.removeBindings();
		editManager = manager;
		manager.addModelListener(this);
		if( model != null )
			bindAll();
	}

	public void onChange(Object container) {
		// Optionally overide in concrete form
	}

	public void onContentsChange(Object container) {
		// Optionally overide in concrete form
	}

	public void onModelChange(Object model) {
		// Optionally overide in concrete form
	}

	protected abstract void bindAll();
	
	protected void bind(TextBoxBase widget, Property prop) {
		editManager.addBinding(new TextBoxBinding(model, prop, widget));
	}
	
	protected void bind(CheckBox widget, Property prop) {
		editManager.addBinding(new CheckBoxBinding(model, prop, widget));
	}

	protected void bind(Label widget, Property prop) {
		editManager.addBinding(new LabelBinding(model, prop, widget));
	}
}
